﻿// Implements a container that holds a collection of items
define([
    'Wjs/ui/elements/mixins/Container',
    'Wjs/ui/elements/mixins/Loadable'
],
function () {
    'use strict';

    return Wjs.defineOnce({

        type: 'MultipleContainer',

        internal: {

            base: Wjs.getType('Container'),

            mixins: [
                Wjs.getType('Loadable')
            ],

            construct: function () {

                this.items = [];
            },

            listeners: {

                onDomElementCreated: function () {
                    var fragment;

                    if (this.items &&
                        this.items.length) { // There are items

                        fragment = document.createDocumentFragment();

                        // Render the items elements
                        this.items.forEach(function (item) {

                            item.render(fragment); // If fragment provided, then call fragment.appendChild(item);
                        });

                        this.domEl.appendChild(fragment);

                        // Fire the item rendered event
                        if (this.itemsRenderedHandler) {

                            this.itemsRenderedHandler();
                        }
                    }

                },

                // Called before the element is destroyed
                onDestroy: function () {

                    this.clearItems();
                },

                onCloned: function (cloned) {

                    this.addClonedItemsTo(cloned);
                }
            }

        },

        addItem: function (item, index) {
            var htmlType;

            item = this.createItem(item);

            item.setParent(this);

            // Warn if the item is a Html type since it can change the entire contents of the container if the contents of the Html type are set
            htmlType = Wjs.getType('Html', true); // It is optional since it does not need to be loaded

            if (htmlType && (item instanceof htmlType)) {

                Wjs.log('warn', 'Adding an Html item to the container may change the entire contents of the container if the item has its content set');
            }

            if (!Wjs.isDefined(index)) {

                this.items.push(item); // Append
            }
            else {

                this.items.splice(index, 0, item); // Insert at the specific index
            }

            this.handleItemAdded(item);

            return this;
        },

        addItems: function (items, defaults) {

            if (!items || !items.length) {

                return;
            }

            if (!Wjs.isArray(items)) {

                throw 'The first parameter of the addItems method must be an array';
            }

            items.forEach(function (item) {

                // Apply the default properties to the item configuration if they do not exist
                if (defaults) {

                    Wjs.copyMembers(defaults, item);
                }

                this.addItem(item);
            },
            this);
        },

        addText: function (text) {

            this.addItem(
                Wjs.new('Text').setText(text)
            );

            return this;
        },

        addHtml: function (html) {

            this.addItem(
                Wjs.new('ViewSingleContainer').setHtml(html) // Create a safe type to use the HTML
            );

            return this;
        },

        getItems: function () {

            return this.items;
        },

        getItem: function (index) {

            return this.items[index];
        },

        // Recursively returns all the items of this view that match the criteria of the test function
        down: function (test, output) {
            var done = false;

            if (!output) { // Assume parent will not provide the output array

                output = [];
                done = true;
            }

            this.items.forEach(function (item) {

                if (!test || test(item)) {

                    output.push(item);
                }

                if (item.down) { // Recurse

                    item.down(test, output);
                }
            },
            this);

            if (done) {

                return output;
            }
        },

        // Removes the item from the collection of items
        removeItem: function (index, keepAlive) {
            var item = this.getItem(index);

            if (!item) {

                throw 'Item not found for index: ' + index;
            }

            this.items.splice(index, 1);

            if (!keepAlive) {

                item.destroy();
            }

            if (this.itemRemovedHandler) {

                this.itemRemovedHandler(item);
            }
        },

        replaceItem: function (oldChild, newChild) {
            var index = Wjs.array.indexOf(this.items, function (ch) {
                return oldChild === ch;
            });

            oldChild.setParent(null);

            this.items[index] = newChild;

            if (this.isRendered()) {

                throw 'Implement replacing the items in the DOM';
            }
        },

        // Removes all the items of this component
        clearItems: function () {

            if (this.items) {

                this.items.forEach(function (item) {

                    item.destroy();
                },
                this);
            }

            this.items.length = 0; // Reset the array

            if (this.itemsClearedHandler) {

                this.itemsClearedHandler();
            }
        },

        beforeLoadHandler: function () {

            this.clearItems();
        },

        loadHandler: function (data, contentType) {
            var item;

            if (contentType != 'json') {

                throw 'Only JSON content type is supported for MultipleContainer';
            }

            data.forEach(function (dataItem) {

                item = this.createItem({}, this.defaultItemType || 'ViewSingleContainer');

                this.addItem(item);

                if (item.setHtml && this.template) {

                    item.setHtml(this.template(dataItem));
                }
                else if (item.setHtml && this.draw) {

                    item.setHtml(this.draw(dataItem));
                }
                else if (item.loadData) {

                    item.loadData(dataItem, contentType);
                }

                item.record = dataItem;
            },
            this);
        },

        // Shows the items that pass the test function, else hide them
        filterItems: function (test) {

            if (!test) {

                throw 'Test function is required';
            }

            this.items.forEach(function (item) {

                if (test(item)) {

                    item.show();
                }
                else {

                    item.hide();
                }
            },
            this);
        },

        addClonedItemsTo: function (container) {

            this.items.forEach(function (item) {
                var clonedItem = item.clone();

                container.addItem(clonedItem);
            });
        }
    });

});